home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_07_01 / v7n1060a.txt < prev    next >
Text File  |  1988-09-12  |  6KB  |  270 lines

  1. /*
  2.  * dirret.c    MS-DOS and Unix portable directory builder.
  3.  *
  4.  *        Routines:
  5.  *
  6.  *        struct dir_retrieve_t *
  7.  *        dir_retrieve( path, dir_entries );
  8.  *
  9.  *        void
  10.  *        dir_free( dir_ptr );
  11.  *
  12.  *        usage:    dir_retrieve( "/usr/include", &count );
  13.  *
  14.  *        Possible errno:    ENOENT, ENOTDIR and ENOMEM
  15.  *
  16.  * (c) Copyright 1988 Aspen Scientific
  17.  * All Rights Reserved.
  18.  */
  19. #include <stdio.h>
  20. #include <malloc.h>
  21. #include <errno.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include "dirret.h"    /* the dir header file */
  25.  
  26. #ifdef A_MSDOS
  27. # include <dos.h>    /* MSC 5.0 include for reading directories */
  28. static struct find_t find_buf;
  29. #endif
  30.  
  31. #ifdef A_UNIX
  32. /* sys/dir.h: incl by dirret.h: Unix Sys 5 include for reading directories */
  33. static struct direct find_buf;
  34. #endif
  35.  
  36. /* helper routines and data
  37.  */
  38. #ifdef A_ANSI
  39.  
  40. static int    dir_prep( char * );
  41. static int    dir_next( char *, struct dir_retrieve_t *, int * );
  42.  
  43. #else
  44.  
  45. static int    dir_prep();
  46. static int    dir_next();
  47.  
  48. #endif
  49.  
  50. static int    dir_fdesc;        /* for Unix, hold file descriptor */
  51. static char *    dir_stat;        /* used to stat() the entry name */
  52. extern int    strcmp();        /* for qsort() */
  53. extern int    errno;            /* for reporting errors */
  54.  
  55. /* dir_retrieve builds a sorted directory listing of the directory
  56.  *        referenced by path.  a pointer to an array of structs
  57.  *        of file name strings is returned.  the list end is marked
  58.  *        by a NULL byte in the first element of the name.
  59.  */
  60.  
  61. struct dir_retrieve_t *
  62. dir_retrieve( path, dir_entries )
  63. char *path;
  64. int *dir_entries;
  65. {
  66.     register int slots=ALLOC_UNIT, cnt=0, nm=0;
  67.     struct dir_retrieve_t *dir = (struct dir_retrieve_t *)0, *tmp;
  68.     int dir_hold=1;            /* for MS-DOS, hold find first */
  69.  
  70.     /* prepare the directory for reading.
  71.      * if return zero, the prep failed.
  72.      */
  73.     if (!dir_prep( path ))
  74.         return ( dir );
  75.  
  76.     /* start with minimum allocation
  77.      */
  78.     if (!(dir = (struct dir_retrieve_t *)malloc(
  79.         (slots * sizeof ( struct dir_retrieve_t ))))) {
  80.  
  81.         errno = ENOMEM;
  82.         return ( 0 );
  83.     }
  84.  
  85.     while ( 1 ) {
  86.  
  87.         /* check for list overflow
  88.          */
  89.         if (cnt == ALLOC_UNIT) {
  90.             slots += ALLOC_UNIT;
  91.  
  92.             /* the first time malloc(), then realloc().
  93.              */
  94.             tmp = dir;
  95.             dir = (struct dir_retrieve_t *)realloc( dir,
  96.                 (slots * sizeof ( struct dir_retrieve_t )));
  97.  
  98.             /* out of memory
  99.              */
  100.             if (dir == (struct dir_retrieve_t *)0) {
  101.                 free ( tmp );
  102.                 errno = ENOMEM;
  103.                 return ( dir );
  104.             }
  105.  
  106.             cnt = 0;    /* reset counter */
  107.         }
  108.  
  109.         /* get the next file name, if existing
  110.          */
  111.         if (!dir_next( path, &dir[ nm ], &dir_hold )) {
  112.             *dir[ nm ].name = '\0';
  113.             break;
  114.         }
  115.  
  116.         ++nm;
  117.         ++cnt;
  118.     }
  119.  
  120.     qsort( dir, nm, sizeof (struct dir_retrieve_t), strcmp );
  121.  
  122.     /* only set if the caller passed a valid pointer
  123.      */
  124.     if ( dir_entries != (int *)0 )
  125.         *dir_entries = nm;
  126.  
  127.     return ( dir );
  128. }
  129.  
  130. /* dir_prep    readies the directory interface for retrieving names
  131.  *        from the directory.  if this fails, it means that the
  132.  *        directory referenced is un-readable.
  133.  */
  134.  
  135. static int
  136. dir_prep( path )
  137. char *path;
  138. {
  139. #ifdef A_MSDOS
  140.     char *ppath;
  141.     static char *ext = "/*.*";
  142.  
  143.     if ((ppath = malloc( strlen( path )+strlen( ext ) )) == (char *)0) {
  144.         errno = ENOMEM;
  145.         return ( 0 );
  146.     }
  147.  
  148.     /* protect against building string like: "//*.*"
  149.      */
  150.     strcpy( ppath, path );
  151.     strcat( ppath, (strcmp( ppath, "/" ) ? ext:ext+1) );
  152.  
  153.     /* _A_SUBDIR means read all files, both regular and
  154.      * sub-directories. findfirst return of 0 is good.
  155.      */
  156.     if (_dos_findfirst( ppath, _A_SUBDIR, &find_buf ) != 0) {
  157.         free( ppath );
  158.         errno = ENOENT;
  159.         return ( 0 );
  160.     }
  161.  
  162.     free( ppath );
  163. #else
  164.     struct stat stat_buf;
  165.  
  166.     /* open the directory
  167.      */
  168.     if ((dir_fdesc = open( path, 0 )) == (-1)) {
  169.         errno = ENOENT;
  170.         return ( 0 );
  171.     }
  172.  
  173.     /* see if it is a regular file or a directory
  174.      */
  175.     fstat( dir_fdesc, &stat_buf );
  176.     if ( (stat_buf.st_mode & S_IFDIR) == 0 ) {
  177.         close( dir_fdesc );
  178.         errno = ENOTDIR;
  179.         return ( 0 );
  180.     }
  181. #endif
  182.  
  183.     /* allocate a buffer to contain:
  184.      *
  185.      * path/entry_name for stat()'ing
  186.      */
  187.     if ((dir_stat = malloc( strlen( path )+_FN_SZ+1 )) == (char *)0) {
  188. #ifdef A_UNIX
  189.         close( dir_fdesc );
  190. #endif
  191.         errno = ENOMEM;
  192.         return ( 0 );
  193.     }
  194.  
  195.     return ( 1 );
  196. }
  197.  
  198. /* dir_next    return the next entry in the directory.  a NULL pointer
  199.  *        says no more entries.
  200.  */
  201. static int
  202. dir_next( path, transfer, dir_hold )
  203. char *path;
  204. struct dir_retrieve_t *transfer;
  205. int *dir_hold;
  206. {
  207.     struct stat stat_buf;
  208.  
  209. #ifdef A_MSDOS
  210.     /* are we holding from the find first?
  211.      * if so, skip the find next this time.
  212.      */
  213.     if (! *dir_hold) {
  214.         /* findnext return of 0 is good.
  215.          */
  216.         if (_dos_findnext( &find_buf ) != 0) {
  217.             free( dir_stat );
  218.             return ( 0 );
  219.         }
  220.     }
  221.     else
  222.         *dir_hold = 0;    /* next call will do _dos_findnext() */
  223.  
  224.     strcpy( transfer->name, find_buf.name );
  225. #else
  226.     register int i;
  227.  
  228.     while ( 1 ) {
  229.         i = read(dir_fdesc, &find_buf, sizeof (struct direct));
  230.  
  231.         if (i != sizeof (struct direct)) {
  232.             close( dir_fdesc );
  233.             free( dir_stat );
  234.             return ( 0 );
  235.         }
  236.         else if (find_buf.d_ino != 0)    /* empty? */
  237.             break;
  238.     }
  239.  
  240.     /* since d_name is only NULL terminated if the file name is
  241.      * less than DIRSIZ, we cannot use strcpy() here.
  242.      */
  243.     for (i=0; i < DIRSIZ && find_buf.d_name[i]; ++i)
  244.         transfer->name[i] = find_buf.d_name[i];
  245.     transfer->name[i] = '\0';
  246. #endif
  247.  
  248.     strcpy( dir_stat, path );
  249.     if (strcmp( path, "/" ) != 0)
  250.         strcat( dir_stat, "/" );
  251.     strcat( dir_stat, transfer->name );
  252.  
  253.     /* is it a sub-directory?
  254.      */
  255.     stat( dir_stat, &stat_buf );
  256.     transfer->subdir = ( (stat_buf.st_mode & S_IFDIR) ? 1:0 );
  257.  
  258.     return ( 1 );
  259. }
  260.  
  261. /* dir_free    calls free for the given directory pointer
  262.  */
  263.  
  264. void
  265. dir_free( dir )
  266. struct dir_retrieve_t *dir;
  267. {
  268.     free( (char *)dir );
  269. }
  270.